#include "Bot.h"
#include "MDP.h"
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<fstream>
#include<algorithm>
using namespace std;


//constructor
Bot::Bot()
{

};

//plays a single game of Ants.
void Bot::playGame()
{
    //reads the game parameters and sets up
    cin >> state;
    state.setup();
    endTurn();

    rows = state.rows; cols = state.cols;

    water = new bool[rows*cols];
    seen = new bool[rows*cols];
    moved = new bool[rows*cols];
    safe = new bool[rows*cols];
    designated = new bool[rows*cols];
    occupied = new bool[rows*cols];
    memset(seen, false, sizeof(bool)*cols*rows);
    memset(water, false, sizeof(bool)*rows*cols);

    moveTo = new int[rows*cols];
    memset(moveTo, 0, sizeof(int)*rows*cols);
    opportunitySet = new bool[rows*cols];
    memset(opportunitySet, false, sizeof(bool)*cols*rows);
    
    hills = new int[rows*cols];
    memset(hills, -1, sizeof(int)*cols*rows);
    enemyMap = new int[rows*cols];
    memset(enemyMap, -1, sizeof(int)*cols*rows);

    srand(time(0));

    //continues making moves while the game is not over
    while(cin >> state)
    {
        state.updateVisionInformation();
	initialize();
        makeMoves();
        endTurn();
    }
};

void Bot::initialize(){
     // count the number of our ants
     ants = 0;
     for (int i = 0; i < rows; i++)
	     for (int j = 0; j < cols; j++)
		     if (state.grid[i][j].ant == 0) ants++;

    // update the seen matrix
    for(int i=0; i<rows; i++)
	    for(int j=0; j<cols; j++)
		    if(state.grid[i][j].isVisible)
			    *(seen+i*cols+j) = true;

     // count the seen area
     seenArea = 0;
     for (int i = 0; i < rows; i++)
	     for (int j = 0; j < cols; j++)
		     if (*(seen+i*cols+j)) seenArea++;

     recentlyRate = ceil(((rows*cols) / seenArea) * sqrt(1500/ants));

     // update newly seen hills and cancel destroyed hills
     for (int i=0; i<rows; i++)
	     for (int j=0; j<cols; j++){
		     if (state.grid[i][j].isHill) *(hills+i*cols+j) = state.grid[i][j].hillPlayer;
		     else if (*(hills+i*cols+j) != -1 && state.grid[i][j].isVisible && !state.grid[i][j].isHill)
			     *(hills+i*cols+j) = -1;
	     }

    // reset the possible movements for every ant
    opponents = 0;
    memset(moveTo, 0, sizeof(int)*rows*cols);
    
    // opportunities are not set yet
    opportunitySet = new bool[rows*cols];
    memset(opportunitySet, false, sizeof(bool)*cols*rows);
    
    // reset the enemy map
    memset(enemyMap, -1, sizeof(int)*cols*rows);
    
    // initialize the BFS arrays
    memset(moved, false, sizeof(bool)*rows*cols);
    memset(safe, true, sizeof(bool)*rows*cols);
    memset(designated, false, sizeof(bool)*rows*cols);
    memset(occupied, false, sizeof(bool)*rows*cols);

    for (int row = 0; row < rows; row++)
    for (int col = 0; col < cols; col++) 
	if (state.grid[row][col].ant > 0) 
		for (int i = row - 3; i <= row + 3; i++)
		for (int j = col - 3; j <= col + 3; j++)
			if ((row-i)*(row-i) + (col-j)*(col-j) <= 10)
				safe[((i+rows)%rows)*cols+(j+cols)%cols] = false;

     // dynamic policy part
     if(state.turn == 1 && (int)state.myHills.size()>1){
	     enemyHillReward += 30;
     }
}

//makes the bots moves for the turn
void Bot::makeMoves()
{
    state.bug << "turn " << state.turn << ":" << endl;
    state.bug << state << endl;

    struct visSquare vs[rows][cols];
    
    for (int i=0; i<rows; i++){
	    for (int j=0; j<cols; j++){
		    struct Square sq = state.grid[i][j];
		    if(*(hills+(i*cols+j)) > 0){     // if the square is enemy's hill
			    vs[i][j].reward = enemyHillReward;
			    vs[i][j].updatable = false;
		    }else if(!(*(seen+i*cols+j))){               // if the square is unseen
			    vs[i][j].reward = unseenReward;
			    vs[i][j].updatable = false;
		    }else if(sq.isWater || (*(water+i*cols+j))){                  // if the square is water
			    (*(water+i*cols+j)) = true;
			    vs[i][j].reward = waterReward;
			    vs[i][j].updatable = false;
		    }else if(sq.ant == 0){                 // if the square has our ant
		    }else if(sq.ant > 0 && !sq.isWater){                  // if the square has enemy' ant
			    opponents = sq.ant>opponents?sq.ant:opponents;
			    (*(enemyMap+i*cols+j)) = -2;
		    }else if(*(hills+(i*cols+j)) == 0){    // if the square is our hill
			    if(nearbyEnemies(i, j, defendRadius)>0) continue;
			    else vs[i][j].reward = myHillReward;
		    }
	    }
    }
    
    setAttackOpportunity((struct visSquare *)vs);
    setEnemyReward((struct visSquare *)vs);
    setWaterReward((struct visSquare *)vs);
    
    //  allocate ants to look for food
    for (int i = 0; i < rows; i++)
	    for (int j = 0; j < cols; j++)
		    if (state.grid[i][j].isFood) foodBFS((struct visSquare *)vs, i, j);

    //  allocate ants to keep view of the battle
    for (int i = 0; i < rows; i++){
	    for (int j = 0; j < cols; j++){
		    if (state.grid[i][j].isVisible) vs[i][j].lastSeen = 0; else vs[i][j].lastSeen++; 
		    if (vs[i][j].lastSeen > recentlyRate && !occupied[i*cols + j])
			    viewBFS((struct visSquare *)vs, i, j);
    	    }
    }

    
    // Iteration of MDP value
    for (int iter=0; iter<iteration; iter++){
	    for (int i=0; i<rows; i++)
		    for (int j=0; j<cols; j++)
			    update((struct visSquare *)vs, i, j);
	    for (int i=rows-1; i>=0; i--)
		    for (int j=cols-1; j>=0; j--)
			    update((struct visSquare *)vs, i, j);
	    for (int i=0; i<rows; i++)
		    for (int j=cols-1; j>=0; j--)
			    update((struct visSquare *)vs, i, j);
	    for (int i=rows-1; i>=0; i--)
		    for (int j=0; j<cols; j++)
			    update((struct visSquare *)vs, i, j);
    }
   
    //Prepare the moving sequence
    vector<moveQueue> queue;

    for(int ant=state.myAnts.size()-1; ant>=0; ant--)
    {
	int utility[4], maxMove = -99999;
        int direction = 0;
	Location loc = state.myAnts[ant];
	if (moved[loc.row*cols + loc.col]) continue;

	// calculate the reward plus opportunity
	int checked = 0;
	bool dirCheck[4];
	memset(dirCheck, false, sizeof(bool)*4);
	while (checked < 4){
		int i = rand() % 4;
		if (dirCheck[i]) continue;
		dirCheck[i] = true; 
		checked++;

		utility[i] = getReward((struct visSquare *)vs, loc.row, loc.col, i)
			    + getOpportunity((struct visSquare *)vs, loc.row, loc.col, i);
		if(utility[i]>maxMove){
			maxMove = utility[i];
			direction = i;
		}
	}
	moveQueue newMove;
	newMove.dir = direction;
	newMove.utility = maxMove;
	newMove.row = loc.row;
	newMove.col = loc.col;
	queue.push_back(newMove);
    }
    
    sort(queue.begin(), queue.end(), sequenceSorter());

    // make the moves in order
    for (int i=queue.size()-1; i>=0; i--){
	Location loc(queue[i].row, queue[i].col);
	int direction = queue[i].dir, maxMove = queue[i].utility;
	if (direction == 2) direction = 0;
	else if (direction == 0) direction = 2;
	Location newLoc = state.getLocation(loc, direction);
	if (state.grid[newLoc.row][newLoc.col].ant == 0) { // when the destination is already occupied
		int utility, maxMove = -99999;
		int checked = 0;
		bool dirCheck[4];
		memset(dirCheck, false, sizeof(bool)*4);
		while (checked < 4){
			int i = rand() % 4;
			if (dirCheck[i]) continue;
			dirCheck[i] = true;
			checked++;
			utility = getReward((struct visSquare *)vs, loc.row, loc.col, i)
				    + getOpportunity((struct visSquare *)vs, loc.row, loc.col, i);
			int newDir = i;
			if (newDir == 2) newDir = 0;
			else if (newDir == 0) newDir = 2;
			newLoc = state.getLocation(loc, newDir);
			if(utility > maxMove && state.grid[newLoc.row][newLoc.col].ant == -1){
				maxMove = utility;
				direction = newDir;
			}	
		}
		if (maxMove > vs[loc.row][loc.col].reward+vs[loc.row][loc.col].opportunity) state.makeMove(loc, direction);
		continue;
	}
	if (maxMove > vs[loc.row][loc.col].reward+vs[loc.row][loc.col].opportunity) state.makeMove(loc, direction);
    }

    state.bug << "time taken: " << state.timer.getTime() << "ms" << endl << endl;
};

// Updates the reward of each square in the visible area of an ant
void Bot::update(struct visSquare *vs, int r, int c){
	struct visSquare *curvs = vs+r*cols+c;
	int maxReward = max(0, curvs->reward);
	
	if(!(*curvs).updatable){
		return;
	}
	
	for (int i=0; i<4; i++){
		maxReward = maxReward>getReward(vs, r, c, i)?maxReward:getReward(vs, r, c, i);
	}
	
	(*curvs).reward = maxReward + stepCost;
}

void Bot::setWaterReward(struct visSquare *vs){
	for (int i=0; i<rows; i++){
		for (int j=0; j<cols; j++){
			if((*(water+i*cols+j))){
				(*(vs+i*cols+j)).reward = waterReward;
			}
		}
	}
}

// For a food, search the nearest available ant
void Bot::foodBFS(struct visSquare *vs, int row, int col){
	bfsSquare queue[rows*cols];
	bool visited[rows][cols];
	memset(visited, false, sizeof(bool)*rows*cols);

	int head = 0, tail = 0;
	queue[head].row = row;  queue[head].col = col;  queue[head].dis=0;

	designated[row*cols + cols] = true;
	while (head <= tail) {
		bfsSquare bs = queue[head];
		if (bs.dis > maxDistance) break;
		if (state.grid[bs.row][bs.col].ant == 0){
			if (!moved[bs.row*cols + bs.col]  && 
		    (vs+bs.row*cols+bs.col)->reward + (vs+bs.row*cols+bs.col)->opportunity < thresholdUtility){
				int i;
				for (i = 0; i < state.myAnts.size(); i++) 
					if (state.myAnts[i].row == bs.row && state.myAnts[i].col == bs.col) break;
				Location loc(bs.row, bs.col);

				// do bfs for the ant
				bool visited2[rows][cols];
				memset(visited2, false, sizeof(bool)*rows*cols);
				bfsSquare queue2[rows*cols];

				int head2 = 0, tail2 = 0;
				queue2[head2].row = bs.row;  queue2[head2].col = bs.col;
				queue2[head2].dis = 0;
				while (head2 <= tail2) {
					bfsSquare bs2 = queue2[head2];
					if (bs2.dis == bs.dis) {
						state.makeMove(loc, (bs.lastDir+2)%4);
						loc = state.getLocation(loc, (bs.lastDir+2)%4);
						moved[loc.row*cols + loc.col] = true;
						state.myAnts[i] = loc;	
						break;				
					}
					if (state.grid[bs2.row][bs2.col].isFood && !designated[bs2.row*cols + bs2.col]) break;
					for (int d = 0; d < 4; d ++){
						int newR = (bs2.row + DIRECTIONS[d][0] + rows) % rows,
						    newC = (bs2.col + DIRECTIONS[d][1] + cols) % cols;
						if (!visited2[newR][newC] && safe[newR*cols + newC] && 
						    !state.grid[newR][newC].isWater && *(seen+newR*cols+newC)){
							tail2++;
							queue2[tail2].row = newR; queue2[tail2].col = newC;
							queue2[tail2].dis = bs2.dis + 1;
							visited2[newR][newC] = true;
						}
					}
					head2++;
				}	

			}		
			break;
		}
		for (int d = 0; d < 4; d ++){
			int newR = (bs.row + DIRECTIONS[d][0] + rows) % rows,
			    newC = (bs.col + DIRECTIONS[d][1] + cols) % cols;
			if (!visited[newR][newC] && safe[newR*cols + newC] && 
			    !state.grid[newR][newC].isWater && *(seen+newR*cols+newC)){
				tail++;
				queue[tail].row = newR; queue[tail].col = newC;
				queue[tail].dis = bs.dis + 1;
				queue[tail].lastDir = d;
				visited[newR][newC] = true;
			}
		}
		head++;
	}
}

void Bot::viewBFS(struct visSquare *vs, int row, int col){
	bfsSquare queue[rows*cols];
	bool visited[rows][cols];
	memset(visited, false, sizeof(bool)*rows*cols);

	int head = 0, tail = 0;
	queue[head].row = row;  queue[head].col = col;  queue[head].dis=0;

	for (int i = row - 8; i <= row + 8; i++)
	for (int j = col - 8; j <= col + 8; j++)
		if ((i-row)*(i-row) + (j-col)*(j-col) <= occupyRadius)
			occupied[((i+rows)%rows)*cols + (j+cols)%cols] = true;

	while (head <= tail) {
		bfsSquare bs = queue[head];
		if (bs.dis > maxDistance) break;
		if (state.grid[bs.row][bs.col].ant == 0){
			if (!moved[bs.row*cols + bs.col] && 
		    (vs+bs.row*cols+bs.col)->reward + (vs+bs.row*cols+bs.col)->opportunity < thresholdUtility){
				int i;
				for (i = 0; i < state.myAnts.size(); i++) 
					if (state.myAnts[i].row == bs.row && state.myAnts[i].col == bs.col) break;
				Location loc(bs.row, bs.col);
				state.makeMove(loc, (bs.lastDir+2)%4);
				loc = state.getLocation(loc, (bs.lastDir+2)%4);
				moved[loc.row*cols + loc.col] = true;
				state.myAnts[i] = loc;	
				break;				
			}		
			break;
		}
		for (int d = 0; d < 4; d ++){
			int newR = (bs.row + DIRECTIONS[d][0] + rows) % rows,
			    newC = (bs.col + DIRECTIONS[d][1] + cols) % cols;
			if (!visited[newR][newC] && safe[newR*cols + newC] && 
			    !state.grid[newR][newC].isWater && *(seen+newR*cols+newC)){
				tail++;
				queue[tail].row = newR; queue[tail].col = newC;
				queue[tail].dis = bs.dis + 1;
				queue[tail].lastDir = d;
				visited[newR][newC] = true;
			}
		}
		head++;
	}
}

bool Bot::isFriend(int r, int c, int direction){
	if(direction == 0){
		r = (r+1)%rows;
		return state.grid[r][c].ant==0;
	}else if(direction == 1){
		c = (c+1)%cols;
		return state.grid[r][c].ant==0;
	}else if(direction == 2){
		r = (r-1+rows)%rows;
		return state.grid[r][c].ant==0;
	}else if(direction == 3){
		c = (c-1+cols)%cols;
		return state.grid[r][c].ant==0;
	}
}

int Bot::getOpportunity(struct visSquare *vs, int r, int c, int direction){
	if(direction == 0){
		r = (r+1)%rows;
		return (*(vs+r*cols+c)).opportunity;
	}else if(direction == 1){
		c = (c+1)%cols;
		return (*(vs+r*cols+c)).opportunity;
	}else if(direction == 2){
		r = (r-1+rows)%rows;
		return (*(vs+r*cols+c)).opportunity;
	}else if(direction == 3){
		c = (c-1+cols)%cols;
		return (*(vs+r*cols+c)).opportunity;
	}
}

int Bot::getReward(struct visSquare *vs, int r, int c, int direction){
	if(direction == 0){
		r = (r+1)%rows;
		return (*(vs+r*cols+c)).reward;
	}else if(direction == 1){
		c = (c+1)%cols;
		return (*(vs+r*cols+c)).reward;
	}else if(direction == 2){
		r = (r-1+rows)%rows;
		return (*(vs+r*cols+c)).reward;
	}else if(direction == 3){
		c = (c-1+cols)%cols;
		return (*(vs+r*cols+c)).reward;
	}
}

// count the enemy ants in the range of r(radius)
int Bot::nearbyEnemies(int row, int col, int r){
	int enemiesNum = 0;
	for (int i = row - r; i <= row + r; i++)
		for (int j = col - r; j <= col + r; j++)
			if ((row-i)*(row-i)+(col-j)*(col-j) <= r*r
			    && state.grid[(i + rows) % rows][(j + cols) % cols].ant > 0)
				enemiesNum++;
	return enemiesNum;
}

int Bot::nearbyMyHill(int row, int col, int r){
	int myHillNum = 0;
	for (int i = row - r; i <= row + r; i++)
		for (int j = col - r; j <= col + r; j++)
			if ((row-i)*(row-i)+(col-j)*(col-j) <= r*r 
			     && (*(hills+((i+rows)%rows)*cols+(j+cols)%cols)) == 0)
				myHillNum++;
	return myHillNum;
}

bool Bot::needReinforcement(int row, int col){
	int enemiesNum = 0;
	for (int i = row - 4; i <= row + 4; i++){
		for (int j = col - 4; j <= col + 4; j++){
			if ((row-i)*(row-i)+(col-j)*(col-j) <= 10
			     && state.grid[(i + rows) % rows][(j + cols) % cols].ant > 0){
				return true;
			     }
		}
	}
	
	return false;
}

void Bot::addOpportunity(struct visSquare *vs, int row, int col, int value){
	row = (row+rows)%rows; col = (col+cols)%cols;
	(*(vs+row*cols+col)).opportunity += value;
}

void Bot::setOpportunity(struct visSquare * vs, int row, int col, int value){
	row = (row+rows)%rows; col = (col+cols)%cols;
	(*(vs+row*cols+col)).opportunity = value;
}

void Bot::cluster(int &counter){
	int clusterNo;
	for (int r=0; r<rows; r++){
		for (int c=0; c<cols; c++){
			if ((*(enemyMap+r*cols+c))==-2){
				if(inCluster(r, c, clusterNo)){
					(*(enemyMap+r*cols+c)) = clusterNo;
				}else{
					(*(enemyMap+r*cols+c)) = counter;
					counter += 2;
				}
			}
		}
	}
}

bool Bot::inCluster(int r, int c, int &clusterNo){
	int radius = 2, rsquare = 8;
	for (int i=-radius; i<=radius; i++){
		for (int j=-radius; j<=radius; j++){
			int row = (r+i+rows)%rows, col = (c+j+cols)%cols;
			if(i*i+j*j<=rsquare){
				if((*(enemyMap+row*cols+col))>0){
					clusterNo = (*(enemyMap+row*cols+col));
					return true;
				}
			}
		}
	}
	return false;
}

void Bot::setEnemyReward(struct visSquare *vs){
	if(opponents == 0){
		return;
	}
	
	int counter = 1;
	cluster(counter);
	
	int reward[(counter+1)/2], number[(counter+1)/2];
	
	for (int i=0; i<(counter+1)/2; i++){
		number[i] = 0;
		reward[i] = enemyReward;
	}
	
	for (int i=0; i<rows; i++){
		for (int j=0; j<cols; j++){
			int ant = (*(enemyMap+i*cols+j));
			if(ant>0){
				number[(ant-1)/2]++;
			}
		}
	}
	
	for (int i=0; i<(counter+1)/2; i++){
		reward[i] += 5 * (number[i]/2);
	}
	
	for (int i=0; i<rows; i++){
		for (int j=0; j<cols; j++){
			int ant = (*(enemyMap+i*cols+j));
			if(ant>0){
				if((*(fight+state.grid[i][j].ant*rows*cols+i*cols+j))>3 && adjacentAnt(i, j) == 0){
					// If the current enemy is under attack of more than three ants, no reward is set
					continue;
				}else{
					for (int r = -2; r<=2; r++){
						for(int c = -2; c<=2; c++){
							if( r*r+c*c<=5 && r*r+c*c>=4){
								int row = (i+r+rows)%rows, col = (j+c+cols)%cols;
								if(!state.grid[row][col].isWater){
									(*(vs+row*cols+col)).updatable = false;
									(*(vs+row*cols+col)).reward = reward[(ant-1)/2];
								}
							}
						}
					}
				}
			}
		}
	}
}

void Bot::setAttackOpportunity(struct visSquare *vs){
	if(opponents == 0){
		return;
	}
	
	setFight();
	
	for(int i=0; i<rows; i++){
		for(int j=0; j<cols; j++){
			if(state.grid[i][j].ant == 0 && !state.grid[i][j].isWater){
				for(int d = 0; d<5; d++){
					calOpportunity(vs, i, j, d);
				}
			}
		}
	}
}

void Bot::calOpportunity(struct visSquare *vs, int row, int col, int direction){
	int r, c, fighting;
	if(direction == 0){
		r = (row+1+rows)%rows; c = col;
	}else if(direction == 1){
		r = row; c = (col+1+cols)%cols;
	}else if(direction == 2){
		r = (row-1+rows)%rows; c = col;
	}else if(direction == 3){
		r = row; c = (col-1+cols)%cols;
	}else if(direction == 4){
		r = row; c = col;
	}
	
	fighting = (*(fight+r*cols+c));
	if(fighting==0 || (*(opportunitySet+r*cols+c)) || state.grid[r][c].isWater){
		return;
	}else{
		(*(opportunitySet+r*cols+c)) = true;
	}

	int opportunity, strength, weakest;
	
	strength = bestEnemy(r, c, weakest) - fighting;
	
	/*
	ofstream fout1;
	fout1.open("fight.txt", ios::app);
	fout1 << state.turn << " " << r << " " << c << " " << bestEnemy(r, c, weakest) << " " << fighting << " " << (*(moveTo+r*cols+c)) << endl;
	*/
	
	if(strength == 0 && weakest>fighting && fighting==1){
		opportunity = 100 - 20 * (*(moveTo+r*cols+c));
	}else if(strength == 0 && fighting>=3 && direction==4){
		opportunity = 10;
	}else if(strength == 0 && fighting>=3){
		opportunity = -15;
	}else{
		opportunity = 100 * strength - 20 * (*(moveTo+r*cols+c));
	}
	
	addOpportunity(vs, r, c, opportunity);
}

int Bot::bestEnemy(int row, int col, int &weakest){
	int r, c, min = 100, max = 0;
	for(int i=-2; i<=2; i++){
		for(int j=-2; j<=2; j++){
			if(i*i+j*j<=5){
				r = (row+i+rows)%rows; c = (col+j+cols)%cols;
				for(int p=1; p<=opponents; p++){
					int fighting = (*(fight+p*rows*cols+r*cols+c));
					if(fighting>0 && fighting<min){
						min = fighting;
					}
					if(fighting>0 && fighting>max){
						max = fighting;
					}
				}
			}
		}
	}
	weakest = max;
	return min;
}

void Bot::setFight(){
	if(totalInfluence == NULL){
		delete [] totalInfluence;
		delete [] influence;
		delete [] fight;
	}
	totalInfluence = new int[rows*cols];
	influence = new int[(opponents+1)*rows*cols];
	fight = new int[(opponents+1)*rows*cols];
	
	memset(totalInfluence, 0, sizeof(int)*rows*cols);
	memset(influence, 0, sizeof(int)*(opponents+1)*rows*cols);
	memset(fight, 0, sizeof(int)*(opponents+1)*rows*cols);
	
	for(int i=0; i<rows; i++){
		for(int j=0; j<cols; j++){
			if(state.grid[i][j].ant != -1 && !state.grid[i][j].isWater){
				addInfluence(state.grid[i][j].ant, i, j);
			}
		}
	}
	
	for(int i=0; i<rows; i++){
		for(int j=0; j<cols; j++){
			if(state.grid[i][j].ant != -1 && !state.grid[i][j].isWater){
				for(int d=0; d<5; d++){
					calFight(state.grid[i][j].ant, i, j, d);
				}
			}
		}
	}
}

void Bot::calFight(int player, int row, int col, int direction){
	int r, c;
	if(direction == 0){
		r = (row+1+rows)%rows; c = col;
	}else if(direction == 1){
		r = row; c = (col+1+cols)%cols;
	}else if(direction == 2){
		r = (row-1+rows)%rows; c = col;
	}else if(direction == 3){
		r = row; c = (col-1+cols)%cols;
	}else if(direction == 4){
		r = row; c = col;
	}
	
	(*(fight+player*rows*cols+r*cols+c)) = (*(totalInfluence+r*cols+c)) - (*(influence+player*rows*cols+r*cols+c));
}

void Bot::addInfluence(int player, int row, int col){
	int r[5], c[5];
	bool movable[4];
	
	r[0] = (row+1+rows)%rows; c[0] = col;
	r[1] = row; 		  c[1] = (col+1+cols)%cols;
	r[2] = (row-1+rows)%rows; c[2] = col;
	r[3] = row; 		  c[3] = (col-1+cols)%cols;
	r[4] = row; 		  c[4] = col;
	
	for(int d=0; d<4; d++){
		if(state.grid[r[d]][c[d]].isWater || state.grid[r[d]][c[d]].ant != -1){
			movable[d]=false;
		}else if((*(moveTo+r[d]*cols+c[d]))>0){
			(*(moveTo+r[d]*cols+c[d]))++;
			movable[d]=false;
		}else{
			(*(moveTo+r[d]*cols+c[d]))++;
			movable[d]=true;
		}
	}
	(*(moveTo+r[4]*cols+c[4]))++;
	
	if(movable[0]){
		for (int j=-1; j<=1; j++){
			(*(influence+player*rows*cols+((r[0]+2+rows)%rows)*cols+(c[0]+j+cols)%cols))++;
			(*(totalInfluence+((r[0]+2+rows)%rows)*cols+(c[0]+j+cols)%cols))++;
		}
	}
	if(movable[1]){
		for (int i=-1; i<=1; i++){
			(*(influence+player*rows*cols+((r[1]+i+rows)%rows)*cols+(c[1]+2+cols)%cols))++;
			(*(totalInfluence+((r[1]+i+rows)%rows)*cols+(c[1]+2+cols)%cols))++;
		}
	}
	if(movable[2]){
		for (int j=-1; j<=1; j++){
			(*(influence+player*rows*cols+((r[2]-2+rows)%rows)*cols+(c[2]+j+cols)%cols))++;
			(*(totalInfluence+((r[2]-2+rows)%rows)*cols+(c[2]+j+cols)%cols))++;
		}
	}
	if(movable[3]){
		for (int i=-1; i<=1; i++){
			(*(influence+player*rows*cols+((r[3]+i+rows)%rows)*cols+(c[3]-2+cols)%cols))++;
			(*(totalInfluence+((r[3]+i+rows)%rows)*cols+(c[3]-2+cols)%cols))++;
		}
	}
	
	for(int i=-3; i<=3; i++){
		for (int j=-3; j<=3; j++){
			if(i*i+j*j<=5){
				(*(influence+player*rows*cols+((r[4]+i+rows)%rows)*cols+(c[4]+j+cols)%cols))++;
				(*(totalInfluence+((r[4]+i+rows)%rows)*cols+(c[4]+j+cols)%cols))++;
			}
		}
	}
	
	if(movable[0]||movable[1]){
		(*(influence+player*rows*cols+((r[4]+2+rows)%rows)*cols+(c[4]+2+cols)%cols))++;
		(*(totalInfluence+((r[4]+2+rows)%rows)*cols+(c[4]+2+cols)%cols))++;
	}
	if(movable[1]||movable[2]){
		(*(influence+player*rows*cols+((r[4]-2+rows)%rows)*cols+(c[4]+2+cols)%cols))++;
		(*(totalInfluence+((r[4]-2+rows)%rows)*cols+(c[4]+2+cols)%cols))++;
	}
	if(movable[2]||movable[3]){
		(*(influence+player*rows*cols+((r[4]-2+rows)%rows)*cols+(c[4]-2+cols)%cols))++;
		(*(totalInfluence+((r[4]-2+rows)%rows)*cols+(c[4]-2+cols)%cols))++;
	}
	if(movable[3]||movable[0]){
		(*(influence+player*rows*cols+((r[4]+2+rows)%rows)*cols+(c[4]-2+cols)%cols))++;
		(*(totalInfluence+((r[4]+2+rows)%rows)*cols+(c[4]-2+cols)%cols))++;
	}
}

int Bot::adjacentAnt(int row, int col){
	int count = 0;
	if(state.grid[(row+1)%rows][(col)%cols].ant>0) count++;
	if(state.grid[(row)%rows][(col+1)%cols].ant>0) count++;
	if(state.grid[(row-1)%rows][(col)%cols].ant>0) count++;
	if(state.grid[(row)%rows][(col-1)%cols].ant>0) count++;
	return count;
}



//finishes the turn
void Bot::endTurn()
{
    if(state.turn > 0)
        state.reset();
    state.turn++;

    cout << "go" << endl;
};

